﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using System.IO;
using System.Windows.Media.Imaging;
using DevExpress.Xpf.Utils;

namespace Cinser.Common.Resources
{

    public static class ImageSourceHelper
    {
        class EmbeddedResourceUri
        {
            public EmbeddedResourceUri(Assembly assembly, string name, bool isNameFull)
            {
                Assembly = assembly;
                Name = name;
                IsNameFull = isNameFull;
            }
            public Assembly Assembly { get; private set; }
            public string Name { get; private set; }
            public bool IsNameFull { get; private set; }
            public override bool Equals(object obj)
            {
                EmbeddedResourceUri uri = obj as EmbeddedResourceUri;
                if (uri == null) return false;
                if (!object.Equals(Assembly, uri.Assembly)) return false;
                if (!object.Equals(Name, uri.Name)) return false;
                if (!object.Equals(IsNameFull, uri.IsNameFull)) return false;
                return true;
            }
            public override int GetHashCode()
            {
                int hash = 0;
                hash += Assembly == null ? 0 : Assembly.GetHashCode();
                hash += Name == null ? 0 : Name.GetHashCode();
                hash += IsNameFull.GetHashCode();
                return hash;
            }
        }
        #region Dependency Properties
        static readonly DependencyProperty SourceUriProperty;
        static ImageSourceHelper()
        {
            Type ownerType = typeof(ImageSourceHelper);
            SourceUriProperty = DependencyProperty.RegisterAttached("SourceUri", typeof(EmbeddedResourceUri), ownerType, new PropertyMetadata(null));
        }
        #endregion
        static EmbeddedResourceUri GetSourceUri(ImageSource imageSource) { return (EmbeddedResourceUri)imageSource.GetValue(SourceUriProperty); }
        static void SetSourceUri(ImageSource imageSource, EmbeddedResourceUri uri) { imageSource.SetValue(SourceUriProperty, uri); }
        static Dictionary<EmbeddedResourceUri, ImageSource> imageSources = new Dictionary<EmbeddedResourceUri, ImageSource>();

        public static ImageSource CreateImageFromEmbeddedResource(Assembly assembly, string name, bool isNameFull)
        {
            EmbeddedResourceUri uri = new EmbeddedResourceUri(assembly, name, isNameFull);
            ImageSource imageSource;
            if (imageSources.TryGetValue(uri, out imageSource)) return imageSource;
            Stream stream = AssemblyHelper.GetEmbeddedResourceStream(assembly, name, isNameFull);
            imageSource = CreateImageSourceFromStream(stream);
            SetSourceUri(imageSource, uri);
            imageSources.Add(uri, imageSource);
            return imageSource;
        }
        public static string ImageSourceToString(ImageSource imageSource)
        {
            BitmapImage bitmapImage = imageSource as BitmapImage;
            if (bitmapImage == null) return string.Empty;
            if (bitmapImage.UriSource == null) return EmbeddedResourceImageSourceToString(imageSource);
            return string.Format(bitmapImage.UriSource.IsAbsoluteUri ? "a{0}" : "r{0}", bitmapImage.UriSource);
        }
        public static ImageSource ImageSourceFromString(string s)
        {
            if (string.IsNullOrEmpty(s)) return null;
            try
            {
                if (s[0] == 'e') return EmbeddedResourceImageSourceFromString(s);
                bool absolute = s[0] == 'a';
                string uriString = s.Substring(1);
                return new BitmapImage(new Uri(uriString, absolute ? UriKind.Absolute : UriKind.Relative));
            }
            catch
            {
                return null;
            }
        }
        static string EmbeddedResourceImageSourceToString(ImageSource imageSource)
        {
            EmbeddedResourceUri uri = GetSourceUri(imageSource);
            if (uri == null) return string.Empty;
            return string.Format("e{0}/{1}/{2}", uri.Assembly.FullName, uri.Name, uri.IsNameFull);
        }
        static ImageSource EmbeddedResourceImageSourceFromString(string s)
        {
            string[] parts = s.Substring(1).Split('/');
            if (parts.Length != 3) return null;
            Assembly assembly = AssemblyHelper.GetAssembly(parts[0]);
            if (assembly == null) return null;
            return CreateImageFromEmbeddedResource(assembly, parts[1], bool.Parse(parts[2]));
        }
        static ImageSource CreateImageSourceFromStream(Stream stream)
        {
            if (stream == null) return null;
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.StreamSource = stream;
            bi.EndInit();
            return bi;
        }
    }
}
